home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / SDKs / Word Services SDK 1.0.6 / Writeswell Jr 1.2.1 Sources ƒ / Writeswell Jr. Source / DoChecking.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-09-16  |  14.4 KB  |  599 lines  |  [TEXT/KAHL]

  1. /* DoChecking.c
  2.  * Functions that actually do the calls to the Word Services servers.
  3.  * ©1992 Working Software, Inc.
  4.  * This source code is copyrighted.  Permission is granted to use the Word Services
  5.  * portion of the Writeswell Jr. source code in your own programs, but you 
  6.  * may not distribute the Writeswell Jr. word-processor code as a 
  7.  * commercial product.  If you modify the code, please do not call it 
  8.  * Writeswell Jr. (or Writeswell.)  This will ensure that people understand the 
  9.  * program and don’t have to deal with a number of different versions with 
  10.  * who-knows-what going on in the code.
  11.  * 
  12.  * Writeswell Jr. and Writeswell are trademarks of Working Software, Inc.
  13.  * 28 Dec 91 Mike Crawford
  14.  */
  15.  
  16. #include <Aliases.h>
  17. #include <Processes.h>
  18. #include <AppleEvents.h>
  19. #include <AEObjects.h>
  20. #include <AEPackObject.h>
  21. #include <AERegistry.h>
  22. #include "TBConstants.h"
  23. #include "TBGlobals.h"
  24. #include "WordServices.h"
  25. #include "AppEvents.h"
  26. #include "ObWind.h"
  27. #include "ObText.h"
  28. #include "Gripe.h"
  29. #include "Prefs.h"
  30. #include "DoChecking.h"
  31. #include "FindProcess.h"
  32. #include "TableCheck.h"
  33.  
  34. #define LAUNCH_BY_EVENT            /* Undef this to use Proc Mgr instead of Finder AE */
  35.  
  36. #define kLaunchTimeout    1800    /* If the speller's on a floppy, it may take a while */
  37. #define kBatchTimeout    600
  38.  
  39. OSErr LaunchSpeller( AliasHandle aliasHdl );
  40.  
  41. OSErr DoSpellCheck( short serviceNumber )
  42. {
  43.     OSErr            err;
  44.     AEDesc            docSpecifier;
  45.     AEDesc            textDescriptor;
  46.     AEDesc            textSpecifier;
  47.     AEAddressDesc    spellerAddr;
  48.     AppleEvent        btchEvent;
  49.     AppleEvent        replyEvent;
  50.     WWJrPrefsHdl    prefHdl;
  51.     ServiceType        servType;
  52.  
  53.     prefHdl = GetPrefHandle();
  54.     if ( !prefHdl ){
  55.         Gripe( "\pCannot get preferences handle" );
  56.         return resNotFound;
  57.     }
  58.  
  59.     err = OpenSpeller( serviceNumber, &spellerAddr, &servType );
  60.     if ( err ){
  61.         Gripe( "\pOpenSpeller failed to connect with speller" );
  62.         return err;
  63.     }
  64.  
  65.     switch ( servType ){
  66.         case kBatchService:
  67.             if ( (*prefHdl)->sendByList ){
  68.                 err = DoBatchCheck( &spellerAddr );
  69.                 if ( err ){
  70.                     Gripe( "\pDoBatchCheck failed" );
  71.                     return err;
  72.                 }
  73.             }else{
  74.                 err = DoBatchTableCheck( &spellerAddr );
  75.                 if ( err ){
  76.                     Gripe( "\pDoBatchTableCheck failed" );
  77.                     return err;
  78.                 }
  79.             }
  80.             break;
  81.         case kInteractiveService:
  82.             Gripe( "\pInteractive service is not implemented yet" );
  83.             return noErr;
  84.             break;
  85.         default:
  86.             Gripe( "\pBad service type code in preferences file" );
  87.             return noErr;
  88.     }
  89.  
  90.     return noErr;
  91. }
  92.  
  93. OSErr DoBatchCheck( AEAddressDesc *spellerAddrPtr )
  94. {
  95.     OSErr            err;
  96.     AEDesc            textSpecifier;
  97.     AppleEvent        btchEvent;
  98.     AppleEvent        replyEvent;
  99.     WWJrPrefsHdl    prefHdl;
  100.     AEDescList        textSpecList;            /* 1.0d7 */
  101.     long            index;                    /* 1.0d7 */
  102.  
  103.     /* We make an object specifier that refers to _our_own_ window
  104.      */
  105.  
  106.     err = CreateTextSpecifier( 1L, 1L, &textSpecifier );
  107.     
  108.     if ( err ){
  109.         Gripe( "\pCreateTextSpecifier failed" );
  110.         return err;
  111.     }
  112.  
  113.     prefHdl = GetPrefHandle();
  114.     if ( !prefHdl ){
  115.         Gripe( "\pCannot get preferences handle" );
  116.         return resNotFound;
  117.     }
  118.     
  119.     if ( (*prefHdl)->checkSel ){
  120.         /* Make a formRange descriptor that gives the selection range */
  121.  
  122.         Gripe( "\pSelection-only checking is not yet implemented" );
  123.         return noErr;
  124.     }
  125.  
  126.     /* Create the event to send to the speller */
  127.     
  128.     err = AECreateAppleEvent( kWordServicesClass,
  129.                                 kWSBatchCheckMe,
  130.                                 spellerAddrPtr,
  131.                                 kAutoGenerateReturnID,
  132.                                 kAnyTransactionID,
  133.                                 &btchEvent );
  134.     
  135.     if ( err ){
  136.         Gripe( "\pcreate btch event failed" );
  137.         return err;
  138.     }
  139.     err = AEDisposeDesc( spellerAddrPtr );
  140.     if ( err ){
  141.         Gripe( "\pAEDisposeDesc failed" );
  142.         return err;
  143.     }
  144.  
  145. #ifdef OLD_SPEC    
  146.  
  147.     /* This was used until 1.0d6 */
  148.  
  149.     /* Insert the object specifier as the direct object of the batch event */
  150.  
  151.     err = AEPutParamDesc( &btchEvent,
  152.                             keyDirectObject,
  153.                             &textSpecifier );
  154.     if ( err ){
  155.         Gripe( "\pAEPutParamDesc failed to put direct object on batch event" );
  156.         return err;
  157.     }
  158.     err = AEDisposeDesc( &textSpecifier );
  159.     if ( err ){
  160.         Gripe( "\pAEDisposeDesc failed" );
  161.         return err;
  162.     }
  163. #else
  164.  
  165.     /* 1.0d7 This is the new way to do it - use a list of object specifiers (even if
  166.      * only one of them
  167.      */
  168.     
  169.     err = AECreateList( (Ptr)NULL, (Size)0, false, &textSpecList );
  170.     if ( err ){
  171.         Gripe( "\pAECreateList failed" );
  172.         return err;
  173.     }
  174.     
  175.     /* Put our specifier into it.  If we had multiple text blocks to check, we would
  176.      * put specifiers for each into it in turn.
  177.      * Note that we use AEPutDesc, not AEPutParamDesc, to put items into an indexed
  178.      * list.
  179.      */
  180.  
  181. #define N_TEXT_SPECS    1L /*3L    */    /* Define this to be 1 for normal checking */
  182.  
  183.     for ( index = 1L; index <= N_TEXT_SPECS; index++ ){
  184.         err = AEPutDesc( &textSpecList,
  185.                             index,
  186.                             &textSpecifier );
  187.         if ( err ){
  188.             Gripe( "\pAEPutDesc failed to put text specifier into textSpecList" );
  189.             return err;
  190.         }
  191.     }
  192.  
  193.     err = AEDisposeDesc( &textSpecifier );
  194.     if ( err ){
  195.         Gripe( "\pAEDisposeDesc failed" );
  196.         return err;
  197.     }
  198.  
  199.     /* Insert the list of object specifiers as the direct object of the batch event */
  200.  
  201.     err = AEPutParamDesc( &btchEvent,
  202.                             keyDirectObject,
  203.                             &textSpecList );
  204.     if ( err ){
  205.         Gripe( "\pAEPutParamDesc failed to put direct object on batch event" );
  206.         return err;
  207.     }
  208.     
  209.     /* 1.0.3 MDC fixed a bug in which we disposed of textSpecifier a second
  210.      * time, instead of properly disposing of textSpecList
  211.      */
  212.  
  213.     err = AEDisposeDesc( &textSpecList );
  214.     if ( err ){
  215.         Gripe( "\pAEDisposeDesc failed" );
  216.         return err;
  217.     }
  218. #endif
  219.  
  220.     /* Send the event.  We await the reply, so that if there is a failure of some
  221.      * sort in the initial connection, we can alert the user right away.  The timeout
  222.      * value to use here should be as long as one would care to have a user wait for
  223.      * the completion of a menu command.  Since we expect that the speller is on a local
  224.      * machine in this case, and should be able to respond immediately, we just give
  225.      * a few seconds for the timeout.
  226.      *
  227.      * We should assign an idle proc to spin the cursor.  Even better would be a progress
  228.      * dialog that says "Contacting speller" or some such, with an animated display that
  229.      * shows the time elapsed relative to the total timeout, so the user will know how
  230.      * long she may have to wait
  231.      */
  232.     
  233.     err = AESend( &btchEvent,
  234.                     &replyEvent,
  235.                     kAEWaitReply + kAECanInteract + kAECanSwitchLayer,
  236.                     kAENormalPriority,
  237.                     kBatchTimeout,
  238.                     (AEIdleUPP)NULL,
  239.                     (AEFilterUPP)NULL );
  240.     
  241.     if ( err ){
  242.         Gripe( "\psend batch event failed" );
  243.         return err;
  244.     }
  245.     err = AEDisposeDesc( &btchEvent );
  246.     if ( err ){
  247.         Gripe( "\pAEDisposeDesc failed" );
  248.         return err;
  249.     }
  250.     
  251.     /* MDC 1.1.1 fix a memory leak */
  252.  
  253.     err = AEDisposeDesc( &replyEvent );
  254.     if ( err ){
  255.         Gripe( "\pAEDisposeDesc failed" );
  256.         return err;
  257.     }
  258.     
  259.     /* Now the event has been sent.  There is nothing more that we have to actually do
  260.      * on our own initiative to accomplish the spelling; we just sit back and respond
  261.      * to events.  In particular, we don't remember that spelling is taking place - once
  262.      * the spelling is done, we will just start seeing events from the user (mouse and
  263.      * key clicks and so on
  264.      */
  265.     
  266.     return noErr;
  267. }
  268.  
  269. OSErr OpenSpeller( short serviceNumber,
  270.                     AEAddressDesc *spellerAddrPtr,
  271.                     ServiceType *servTypePtr )
  272. {
  273.     WWJrPrefsHdl    prefHdl;
  274.     short            servID;
  275.     AliasHandle        aliasHdl;
  276.     short            curFile;
  277.     OSType            signature;
  278.     ProcessSerialNumber psn;
  279.     ProcessInfoRec        pInfo;
  280.     OSErr            err;
  281.     
  282.     prefHdl = GetPrefHandle();
  283.     if ( !prefHdl ){
  284.         Gripe( "\pCannot get prefs handle" );
  285.         return resNotFound;
  286.     }
  287.     
  288.     servID = gServItemID[ serviceNumber - 1 ];        /* C arrays start at 0 */
  289.     
  290.     *servTypePtr = (*prefHdl)->serviceType[ servID - kServiceBaseID ];
  291.  
  292.     curFile = CurResFile();
  293.     UseResFile( gPrefFileRefNum );
  294.     
  295.     aliasHdl = (AliasHandle)GetResource( rAliasType, servID );
  296.  
  297.     UseResFile( curFile );
  298.  
  299.     if ( !aliasHdl ){
  300.         Gripe( "\pCannot get alias handle for service" );
  301.         return resNotFound;
  302.     }
  303.     
  304.     /* See if the speller is out there */
  305.     signature = (*aliasHdl)->userType;
  306.  
  307.     if ( !FindAProcess( signature, &psn, &pInfo, (FSSpecPtr)NULL, (StringPtr)NULL ) ){
  308.  
  309.         EventRecord event;
  310.         //short        i;
  311.  
  312.         err = LaunchSpeller( aliasHdl );
  313.         if ( err ){
  314.             Gripe( "\pUnable to launch Word Services server" );
  315.             return err;
  316.         }
  317. #ifdef NEVER        
  318.         /* Got to sleep for a little while - otherwise the speller croaks */
  319.         for ( i = 0; i < 10; i++ )
  320.             WaitNextEvent( 0, &event, 1, (RgnHandle)NULL );
  321. #endif
  322.     }    
  323.  
  324.     err = AECreateDesc( typeApplSignature,
  325.                         (Ptr)&signature,
  326.                         sizeof( signature ),
  327.                         spellerAddrPtr );
  328.     if ( err ){
  329.         Gripe( "\pAECreateDesc failed" );
  330.         return err;
  331.     }
  332.     
  333.     return noErr;
  334. }
  335.  
  336. #ifdef LAUNCH_BY_EVENT
  337. OSErr LaunchSpeller( AliasHandle aliasHdl )
  338. {
  339.     OSErr        err;
  340.     FSSpec        spellerSpec;
  341.     Boolean        changed;
  342.     AppleEvent        launchEvent;
  343.     AppleEvent        replyEvent;
  344.     AEDesc            aliasDesc;
  345.     AEDesc            folderDesc;
  346.     FSSpec            folderSpec;
  347.     AEDesc            finderAddr;
  348.     DescType        finderSig;
  349.     AliasHandle        fAliasHdl;
  350.     AEDescList        aliasList;
  351.  
  352.     /* Make sure the speller can still be found, and get its spec */
  353.     err = ResolveAlias( (FSSpecPtr)NULL, aliasHdl, &spellerSpec, &changed );
  354.     
  355.     if ( err ){
  356.         Gripe( "\pCannot locate speller" );        /* Might be user canceled AShare */
  357.         return err;
  358.     }
  359.     
  360.     if ( changed ){
  361.         ChangedResource( (Handle) aliasHdl );
  362.         WriteResource( (Handle) aliasHdl );
  363.     }
  364.     
  365.     /* make an alias for the parent folder */
  366.     
  367.     err = FSMakeFSSpec( spellerSpec.vRefNum,
  368.                         spellerSpec.parID,
  369.                         (StringPtr)NULL,
  370.                         &folderSpec );
  371.     if ( err ){
  372.         Gripe( "\pMakeFSSpec failed" );
  373.         return err;
  374.     }
  375.     
  376.     err = NewAlias( (FSSpecPtr)NULL, &folderSpec, &fAliasHdl );
  377.     if ( err ){
  378.         Gripe( "\pNewAlias failed" );
  379.         return err;
  380.     }
  381.  
  382.     /* Create the event to send to the Finder */
  383.     
  384.     finderSig = 'MACS';                        /* Creator code of finder; type is 'FNDR' */
  385.     err = AECreateDesc( typeApplSignature,
  386.                         (Ptr)&finderSig,
  387.                         sizeof( finderSig ),
  388.                         &finderAddr );
  389.     if ( err ){
  390.         Gripe( "\pAECreateDesc failed" );
  391.         return err;
  392.     }    
  393.                 
  394.     err = AECreateAppleEvent( kAEFinderEvents,
  395.                                 kAEOpenSelection,
  396.                                 &finderAddr,
  397.                                 kAutoGenerateReturnID,
  398.                                 kAnyTransactionID,
  399.                                 &launchEvent );
  400.     
  401.     if ( err ){
  402.         Gripe( "\pcreate open selection event failed" );
  403.         return err;
  404.     }
  405.     err = AEDisposeDesc( &finderAddr );
  406.     if ( err ){
  407.         Gripe( "\pAEDisposeDesc failed" );
  408.         return err;
  409.     }
  410.     
  411.     /* Insert the folder alias record as the direct object of the batch event */
  412.  
  413.     /* First make a descriptor of the alias */
  414.     HLock( (Handle) fAliasHdl );
  415.  
  416.     err = AECreateDesc( typeAlias,
  417.                         (Ptr)*fAliasHdl,
  418.                         (*fAliasHdl)->aliasSize,
  419.                         &folderDesc );
  420.  
  421.     HUnlock( (Handle) fAliasHdl );
  422.     DisposHandle( (Handle) fAliasHdl );
  423.  
  424.     if ( err ){
  425.         Gripe( "\pAECreateDesc failed" );
  426.         return err;
  427.     }    
  428.     
  429.     err = AEPutParamDesc( &launchEvent,
  430.                             keyDirectObject,
  431.                             &folderDesc );
  432.     if ( err ){
  433.         Gripe( "\pAEPutParamDesc failed to put direct object on open selection event" );
  434.         return err;
  435.     }
  436.     err = AEDisposeDesc( &folderDesc );
  437.     if ( err ){
  438.         Gripe( "\pAEDisposeDesc failed" );
  439.         return err;
  440.     }
  441.  
  442.     /* Put the application alias on the event */
  443.     HLock( (Handle) aliasHdl );
  444.  
  445.     err = AECreateDesc( typeAlias,
  446.                         (Ptr)*aliasHdl,
  447.                         (*aliasHdl)->aliasSize,
  448.                         &aliasDesc );
  449.  
  450.     HUnlock( (Handle) aliasHdl );
  451.  
  452.     if ( err ){
  453.         Gripe( "\pAECreateDesc failed" );
  454.         return err;
  455.     }    
  456.  
  457.     /* Now make a list of the alias descriptor.  There is only one element in this
  458.      * list
  459.      */
  460.     
  461.     err = AECreateList( (Ptr)NULL, (Size)0, false, &aliasList );
  462.     
  463.     if ( err ){
  464.         Gripe( "\pAECreateList failed" );
  465.         return err;
  466.     }
  467.     
  468.     err = AEPutDesc( &aliasList, 1L, &aliasDesc );
  469.     
  470.     if ( err ){
  471.         Gripe( "\pAEPutDesc failed to put alias into alias list" );
  472.         return err;
  473.     }
  474.  
  475.     err = AEDisposeDesc( &aliasDesc );
  476.     if ( err ){
  477.         Gripe( "\pAEDisposeDesc failed" );
  478.         return err;
  479.     }
  480.     
  481.     err = AEPutParamDesc( &launchEvent,
  482.                             keySelection,
  483.                             &aliasList );
  484.     if ( err ){
  485.         Gripe( "\pAEPutParamDesc failed to put keySelection on open selection event" );
  486.         return err;
  487.     }
  488.  
  489.     err = AEDisposeDesc( &aliasList );
  490.     if ( err ){
  491.         Gripe( "\pAEDisposeDesc failed" );
  492.         return err;
  493.     }
  494.  
  495.     err = AESend( &launchEvent,
  496.                     &replyEvent,
  497.                     kAEWaitReply + kAECanInteract,        /* Don't allow later switch */
  498.                     kAENormalPriority,
  499.                     kLaunchTimeout,
  500.                     (AEIdleUPP)NULL,
  501.                     (AEFilterUPP)NULL );
  502.     
  503.     if ( err ){
  504.         Gripe( "\psend open selection event failed" );
  505.         return err;
  506.     }
  507.     err = AEDisposeDesc( &launchEvent );
  508.     if ( err ){
  509.         Gripe( "\pAEDisposeDesc failed" );
  510.         return err;
  511.     }
  512.     
  513.     err = AEDisposeDesc( &replyEvent );
  514.     if ( err ){
  515.         Gripe( "\pAEDisposeDesc failed" );
  516.         return err;
  517.     }
  518.     
  519.     return noErr;
  520. }
  521. #else
  522.  
  523. /* This makes the speller fail to process the batch event - I don't know why */
  524.  
  525. OSErr LaunchSpeller( AliasHandle aliasHdl )
  526. {
  527.     LaunchParamBlockRec    pb;
  528.     OSErr        err;
  529.     static FSSpec        spellerSpec;        // See Alan Rosenthal's note below
  530.     Boolean        changed;
  531.     char        *cPtr;
  532.     short        i;
  533.     
  534.     /*
  535.     From: flaps@dgp.toronto.edu (Alan J Rosenthal)
  536.     Subject: astonishing LaunchApplication fact!
  537.     Organization: Dynamic Graphics Project, University of Toronto
  538.     Date: 7 Jul 93 18:58:31 GMT
  539.     Lines: 16
  540.         
  541.     I have discovered that the FSSpec pointed to by the launchAppSpec field in the
  542.     parameter block for LaunchApplication is accessed AFTER LaunchApplication
  543.     RETURNS.  Thus you should not free it immediately afterwards, or if it is a
  544.     local variable of a procedure, you must declare it as static so it persists if
  545.     you're going to return from that procedure in the near future.
  546.     
  547.     This is what my problem last week with regards to launching applications with
  548.     documents was really all about.
  549.     
  550.     It is consistent with my observations for it to be the case that this field is
  551.     accessed only when the application is actually launched, which occurs when you
  552.     do your next WaitNextEvent.  In any case though, this pointer you pass in is
  553.     being held on to for some amount of time.
  554.     
  555.     Alan "an Apple(tm) a day keeps your MacsBug away" Rosenthal
  556.     */
  557.  
  558.     /* Make sure the speller can still be found */
  559.     err = ResolveAlias( (FSSpecPtr)NULL, aliasHdl, &spellerSpec, &changed );
  560.     
  561.     if ( err ){
  562.         Gripe( "\pCannot locate speller" );        /* Might be user canceled AShare */
  563.         return err;
  564.     }
  565.     
  566.     if ( changed ){
  567.         ChangedResource( aliasHdl );
  568.         WriteResource( aliasHdl );
  569.     }
  570.     
  571.     cPtr = (char*)&pb;
  572.     
  573.     for ( i = 0; i < sizeof( pb ); i++ ){
  574.         *cPtr++ = 0;
  575.     }
  576.  
  577.     pb.launchBlockID = extendedBlock;
  578.     pb.launchEPBLength = extendedBlockLen;
  579.     pb.launchControlFlags = launchNoFileFlags + launchContinue /*+ launchDontSwitch*/;
  580.     pb.launchAppSpec = &spellerSpec;
  581.     pb.launchAppParameters = NULL;
  582.     
  583.     err = LaunchApplication( &pb );
  584.     
  585.     if ( err == memFullErr ){
  586.     
  587.         Gripe( "\pThere is not enough memory to launch the Word Services server" );
  588.         return err;
  589.     }
  590.     
  591.     if ( err ){
  592.         Gripe( "\pUnable to launch the Word Services server" );
  593.         return err;
  594.     }
  595.  
  596.     return noErr;
  597. }
  598.  
  599. #endif /* LAUNCH_BY_EVENT */